<?php

namespace app\api\controller\v2;

use app\model\MobileUser;
use EasyWeChat\Factory;
use think\facade\Db;
use think\facade\Log;
use think\Request;


/**
 * 登录.
 */
class Auth extends \app\BaseController
{

    const CACHEEXTIME = 3600 * 24 * 7;
    const TOKENKEY = 'MobileUserToken';

    protected $middleware = [
        \app\middleware\ApiChannel::class,
        \app\middleware\ApiAgentConfig::class,
    ];

    /**
     * 检查是否已经登录.
     */
    public function checkLogin(Request $request)
    {
        $token = $request->header('Authorization');
        $appid = $request->agentConfig['app_id'] ?? '';
        if (empty($token)) {
            return fail('未登录' . $appid);
        }
        $user = Db::name('mobile_user')
            ->where('token', $token)
            ->where('app_id', $appid)
            ->find();
        $now = time();
        if (empty($user) || $user['expired_at'] < $now) {
            return fail('登录过期');
        }
        Db::name('mobile_user')
            ->where('token', $token)
            ->update([
                'expired_at' => $now + self::CACHEEXTIME,
            ]);

        return success('已登录', [
            'token' => $token,
        ]);
    }

    /**
     * 微信公众号登录：根据 code 获取用户 openid.
     */
    public function loginFromCode(Request $request)
    {
        $token = $this->request->header('Authorization');
        if (!empty($token)) {
            $user = Db::name('mobile_user')
                ->where('token', $token)
                ->find();
            $now = time();
            if (!empty($user) && $user['expired_at'] >= $now) {
                Db::name('mobile_user')
                    ->where('id', $user['id'])
                    ->update([
                        'expired_at' => $now + self::CACHEEXTIME,
                    ]);

                return success('已登录', [
                    'token' => $token,
                ]);
            }
        }

//        Log::info('获取到的Appid：'.$request->agentConfig['app_id']);
//        Log::info('获取到的秘钥：'.$request->agentConfig['app_secret']);

        $app = Factory::officialAccount([
            'app_id' => $request->agentConfig['app_id'],
            'secret' => $request->agentConfig['app_secret'],

            // 指定 API 调用返回结果的类型：array(default)/collection/object/raw/自定义类名
            'response_type' => 'array',
        ]);
        try {
            $user = $app->oauth->user();
            $openid = $user->id;
            $token = $this->generateToken();
            if (false === $token) {
                return fail('token 生成失败，请刷新重试');
            }
            $info = Db::name('mobile_user')
                ->field('id, token, expired_at')
                ->where('app_id', $request->agentConfig['app_id'])
                ->where('openid', $openid)
                ->where('agent_id', $request->agentChannel['agent_id'])
                ->find();
            $now = time();
            if ($info) {
                if ($info['expired_at'] > $now) {
                    $token = $info['token'];
                }
                Db::name('mobile_user')
                    ->where('id', $info['id'])
                    ->update([
                        'token' => $token,
                        'expired_at' => $now + self::CACHEEXTIME,
                    ]);
            } else {
                Db::name('mobile_user')->insert([
                    'agent_id' => $request->agentChannel['agent_id'],
                    'app_id' => $request->agentConfig['app_id'],
                    'openid' => $openid,
                    'token' => $token,
                    'expired_at' => $now + self::CACHEEXTIME,
                ]);
            }
        } catch (\Exception $e) {
            return fail('登录失败，请刷新重试:' . $e->getMessage());
        }

        $this->saveTokenToCache($token);

        return success('登录成功', [
            'token' => $token,
        ]);
    }

    /**
     * 根据合作伙伴id获取用户token.
     */
    public function loginFromPartnerId(Request $request)
    {
        $agentId = $request->agentChannel['agent_id'];
        $partnerId = input('post.partnerId');
        if (empty($agentId) || empty($partnerId)) {
            return fail('参数缺失 partnerId');
        }

        try {
            $token = $this->generateToken();
            if (false === $token) {
                return fail('token 生成失败，请刷新重试');
            }
            $info = Db::name('mobile_user')
                ->field('id, token, expired_at')
                ->where('app_id', $request->agentConfig['app_id'])
                ->where('openid', $partnerId)
                ->where('agent_id', $agentId)
                ->find();
            $now = time();
            if ($info) {
                if ($info['expired_at'] > $now) {
                    $token = $info['token'];
                }
                Db::name('mobile_user')
                    ->where('id', $info['id'])
                    ->update([
                        'token' => $token,
                        'expired_at' => $now + self::CACHEEXTIME,
                    ]);
            } else {
                Db::name('mobile_user')->insert([
                    'agent_id' => $agentId,
                    'app_id' => $request->agentConfig['app_id'],
                    'openid' => $partnerId,
                    'token' => $token,
                    'expired_at' => $now + self::CACHEEXTIME,
                ]);
            }
        } catch (\Exception $e) {
            return fail('登录失败，请刷新重试:' . $e->getMessage());
        }


        $this->saveTokenToCache($token);

        return success('登录成功', [
            'token' => $token,
        ]);
    }


    /**
     * 用于请求验证
     * @param $token
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    private function saveTokenToCache($token)
    {
        $user =  MobileUser::query()
            ->where('token', $token)
            ->find();

        if ($user){
            cache(self::TOKENKEY.$token,serialize($user),Auth::CACHEEXTIME-10);
        }
    }


    public function generateToken()
    {
        for ($i = 0; $i < 21; ++$i) {
            $token = md5(microtime(true) . session_create_id());
            $id = Db::name('mobile_user')
                ->where('token', $token)
                ->value('id');
            if (empty($id)) {
                return $token;
            }
        }

        return false;
    }
}
